﻿#include "glcamera.h"

GLCamera::GLCamera()
{

}

GLCamera::GLCamera(const Vector3d &pos, const Vector3d &target, const Vector3d &up)
{
    m_pos = pos;
    m_target = target;
    m_up = up;

	// 构造camera的uvn向量
    n = Vector3d( pos.x()-target.x(), pos.y()-target.y(), pos.z()-target.z());
    u = Vector3d(up.cross(n).x(), up.cross(n).y(), up.cross(n).z());
    v = Vector3d(n.cross(u).x(),n.cross(u).y(),n.cross(u).z());
	// 归一化
    n.normalize();
    u.normalize();
    v.normalize();
	// 设置视点矩阵
    setModelViewMatrix();
}

void GLCamera::setModelViewMatrix()
{
    double m[16];
	// 从世界坐标系到camera的矩阵变换
	// 举例来说：
	// 把摄像机向右移动3个单位，和把物体向左移动3个单位是等效的。
	// 所以物体在世界坐标原点转换到观察坐标（camera）的变换矩阵为：
	// 1 0 0 -m_pos.x
	// 0 1 0 -m_pos.y
	// 0 0 1 -m_pos.z
	// 0 0 0     1

	// 将世界坐标变换到观察（camera）坐标系，设T为世界坐标系矩阵，R为观察（camera）坐标系矩阵
	// 则：
	// S = R 点乘 T，---> S为新的camera坐标矩阵
    m[0]=u.x(); m[4]=u.y(); m[8]=u.z(); m[12]=-m_pos.dot(u);
    m[1]=v.x(); m[5]=v.y(); m[9]=v.z(); m[13]=-m_pos.dot(v);
    m[2]=n.x(); m[6]=n.y(); m[10]=n.z(); m[14]=-m_pos.dot(n);
    m[3]=0;  m[7]=0;  m[11]=0;  m[15]=1.0;
    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixd(m);     //用M矩阵替换原视点矩阵
}

void  GLCamera::setShape(float viewAngle, float aspect, float Near, float Far)
{
	// 初始设置，就像平常的reshape里的一样
	// 设置为投影模式
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();                                   //设置当前矩阵模式为投影矩阵并归一化
	// 透视变换
    gluPerspective(viewAngle,aspect, Near, Far);        //对投影矩阵进行透视变换
}

void GLCamera::slide(float du, float dv, float dn)
{
    //std::cout<<"u.x:"<<u.x()<<std::endl;
    //validate check
    //if the validate checker failed, then it must be an illengle contact
    // in the ohter hand, the reverse direction is acceptale.
    // so, the error direction is needed.

	
	// camera位置变了，
    m_pos(0) = m_pos(0) + du*u.x()+dv*v.x()+dn*n.x();
    m_pos(1) = m_pos(1) + du*u.y() +dv*v.y()+dn*n.y();
    m_pos(2) = m_pos(2) + du*u.z()+dv*v.z()+dn*n.z();

    if (!validate()) {
        m_pos(0) = m_pos(0) - 2*(du*u.x()+dv*v.x()+dn*n.x());
        m_pos(1) = m_pos(1) - 2*(du*u.y()+dv*v.y()+dn*n.y());
        m_pos(2) = m_pos(2) - 2*(du*u.z()+dv*v.z()+dn*n.z());

        m_target(0) = m_target(0)-du*u.x()+dv*v.x()+dn*n.x();
        m_target(1) = m_target(0)-du*u.y()+dv*v.y()+dn*n.y();
        m_target(2) = m_target(0)-du*u.z()+dv*v.z()+dn*n.z();
    }else {
        m_target(0) = m_target(0)+du*u.x()+dv*v.x()+dn*n.x();
        m_target(1) = m_target(0)+du*u.y()+dv*v.y()+dn*n.y();
        m_target(2) = m_target(0)+du*u.z()+dv*v.z()+dn*n.z();
    }

	// 重新设置视点坐标系的矩阵
    setModelViewMatrix();
}

void GLCamera::roll(float angle)
{
    //validate check
    //if (!validate()) return ;
	// 对着视点旋转，n不用变换，u, v变换
    float cs=cos(angle*3.14159265/180);
    float sn=sin(angle*3.14159265/180);
    Vector3d t(u);
    Vector3d s(v);

	// 绕z轴旋转基本形式：
	// x' = x * cos(o) - y * sin(o)
	// y' = x * sin(o) + y * cos(o)
	// z' = z

    u.x() = cs*t.x()-sn*s.x();
    u.y() = cs*t.y()-sn*s.y();
    u.z() = cs*t.z()-sn*s.z();

    v.x() = sn*t.x()+cs*s.x();
    v.y() = sn*t.y()+cs*s.y();
    v.z() = sn*t.z()+cs*s.z();

	// n = n

	// 更新观察矩阵
    setModelViewMatrix();          //每次计算完坐标轴变化后调用此函数更新视点矩阵
}

void GLCamera::pitch(float angle)
{
    //validate check
    //if (!validate()) return ;
	
	//绕x轴旋转
    float cs=cos(angle*3.14159265/180);
    float sn=sin(angle*3.14159265/180);
    Vector3d t(v);
    Vector3d s(n);

	// 基本形式：
	// y' = y * cos(o) - z * sin(o)
	// z' = z * sin(o) + y * cos(o)
	// x' = x

    v.x() = cs*t.x()-sn*s.x();
    v.y() = cs*t.y()-sn*s.y();
    v.z() = cs*t.z()-sn*s.z();

    n.x() = sn*t.x()+cs*s.x();
    n.y() = sn*t.y()+cs*s.y();
    n.z() = sn*t.z()+cs*s.z();

	// u' = u

    setModelViewMatrix();
}

void GLCamera::yaw(float angle)
{
    //validate check
    //if (!validate()) return ;

	//绕y轴旋转
    float cs=cos(angle*3.14159265/180);
    float sn=sin(angle*3.14159265/180);
    Vector3d t(n);
    Vector3d s(u);

	// 基本形式：

	// z' = z * cos(o) - x * sin(o)
	// x' = x * sin(o) + z * con(o)
	// y' = y

    n.x() = cs*t.x()-sn*s.x();
    n.y() = cs*t.y()-sn*s.y();
    n.z() = cs*t.z()-sn*s.z();

    u.x() = sn*t.x()+cs*s.x();
    u.y() = sn*t.y()+cs*s.y();
    u.z() = sn*t.z()+cs*s.z();

	// v' = v

    setModelViewMatrix();
}

float  GLCamera::getDist()
{
	// 到世界坐标原点的距离
    float dist = pow(m_pos.x(),2)+pow(m_pos.y(),2)+pow(m_pos.z(),2);
    return pow(dist,0.5);
}

Vector3d GLCamera::get_pos()
{
    return m_pos;
}

bool GLCamera::validate()
{
    // 检测地面
    if (m_pos.y() + 10 > -1)
        return true;

	// 检测其他物体及碰撞，待实现

    return false;
}
